"""
剪辑决策引擎
根据平台模板和内容分析结果，生成剪辑决策
"""
import logging
from typing import Dict, List, Any, Optional
from datetime import timedelta
import re
from app.exceptions import TemplateNotFoundError

logger = logging.getLogger(__name__)


class DecisionEngine:
    """剪辑决策引擎"""

    def __init__(self):
        # 预定义的平台模板配置
        self.templates = {
            "douyin_short": {
                "name": "抖音短视频",
                "target_duration": 60,  # 目标60秒
                "max_segments": 8,
                "opening_duration": 3,  # 开头3秒
                "ending_duration": 2,   # 结尾2秒
                "content_rules": {
                    "prefer_high_sentiment": True,  # 偏好高情感片段
                    "min_segment_duration": 3,      # 最小片段3秒
                    "max_segment_duration": 15,     # 最大片段15秒
                    "prefer_speech": True,           # 偏好语音片段
                    "avoid_silence": True,           # 避免静音片段
                },
                "editing_rules": {
                    "add_intro": True,              # 添加开头
                    "add_outro": True,              # 添加结尾
                    "transition_style": "cut",      # 转场风格
                    "add_subtitles": True,          # 添加字幕
                }
            },
            "xiaohongshu": {
                "name": "小红书",
                "target_duration": 45,
                "max_segments": 6,
                "opening_duration": 2,
                "ending_duration": 2,
                "content_rules": {
                    "prefer_high_sentiment": True,
                    "min_segment_duration": 4,
                    "max_segment_duration": 12,
                    "prefer_speech": True,
                    "require_complete_sentences": True,  # 需要完整句子
                },
                "editing_rules": {
                    "add_intro": True,
                    "add_outro": True,
                    "transition_style": "fade",
                    "add_subtitles": True,
                    "add_background_music": True,
                }
            },
            "bilibili": {
                "name": "B站",
                "target_duration": 180,  # 3分钟
                "max_segments": 15,
                "opening_duration": 5,
                "ending_duration": 3,
                "content_rules": {
                    "prefer_high_sentiment": False,
                    "min_segment_duration": 5,
                    "max_segment_duration": 30,
                    "prefer_speech": True,
                    "allow_longer_segments": True,
                },
                "editing_rules": {
                    "add_intro": True,
                    "add_outro": True,
                    "transition_style": "dissolve",
                    "add_subtitles": True,
                    "preserve_content_flow": True,  # 保持内容流畅性
                }
            },
            "weibo_video": {
                "name": "微博视频",
                "target_duration": 30,
                "max_segments": 5,
                "opening_duration": 2,
                "ending_duration": 1,
                "content_rules": {
                    "prefer_high_sentiment": True,
                    "min_segment_duration": 2,
                    "max_segment_duration": 10,
                    "prefer_speech": True,
                    "require_high_engagement": True,  # 需要高参与度
                },
                "editing_rules": {
                    "add_intro": True,
                    "add_outro": True,
                    "transition_style": "cut",
                    "add_subtitles": True,
                    "add_text_overlays": True,
                }
            }
        }

    async def generate_editing_decision(
        self,
        semantic_units: List[Dict[str, Any]],
        template_name: str,
        video_duration: float,
        progress_callback=None
    ) -> Dict[str, Any]:
        """
        生成剪辑决策

        Args:
            semantic_units: 语义单元列表
            template_name: 平台模板名称
            video_duration: 视频总时长
            progress_callback: 进度回调函数

        Returns:
            剪辑决策字典
        """
        try:
            if progress_callback:
                progress_callback("加载模板配置", 10)

            # 获取模板配置
            template = self._get_template(template_name)

            if progress_callback:
                progress_callback("分析内容片段", 30)

            # 评估语义单元
            evaluated_units = await self._evaluate_semantic_units(
                semantic_units, template["content_rules"]
            )

            if progress_callback:
                progress_callback("选择剪辑片段", 60)

            # 选择剪辑片段
            selected_segments = await self._select_segments(
                evaluated_units, template, video_duration
            )

            if progress_callback:
                progress_callback("优化剪辑顺序", 80)

            # 优化剪辑顺序和时长
            optimized_segments = await self._optimize_segments(
                selected_segments, template, video_duration
            )

            if progress_callback:
                progress_callback("生成剪辑清单", 100)

            # 生成最终剪辑决策
            editing_decision = {
                "template_name": template_name,
                "template_config": template,
                "total_duration": sum(seg["duration"] for seg in optimized_segments),
                "segments": optimized_segments,
                "editing_instructions": template["editing_rules"],
                "estimated_output_duration": self._estimate_output_duration(
                    optimized_segments, template
                )
            }

            logger.info(f"Editing decision generated: {len(optimized_segments)} segments selected")
            return editing_decision

        except Exception as e:
            logger.error(f"Failed to generate editing decision: {e}")
            raise TemplateNotFoundError(f"生成剪辑决策失败: {e}")

    def _get_template(self, template_name: str) -> Dict[str, Any]:
        """获取模板配置"""
        if template_name not in self.templates:
            raise TemplateNotFoundError(f"未找到模板: {template_name}")

        return self.templates[template_name]

    async def _evaluate_semantic_units(
        self,
        units: List[Dict[str, Any]],
        content_rules: Dict[str, Any]
    ) -> List[Dict[str, Any]]:
        """评估语义单元的适配度"""
        evaluated_units = []

        for unit in units:
            score = 0
            evaluation_reasons = []

            # 基础评分
            base_score = 1.0
            if unit.get("confidence", 0):
                base_score *= unit["confidence"]
            score += base_score

            # 时长评分
            duration = unit.get("duration", 0)
            min_duration = content_rules.get("min_segment_duration", 2)
            max_duration = content_rules.get("max_segment_duration", 20)

            if duration < min_duration:
                score *= 0.5
                evaluation_reasons.append("片段过短")
            elif duration > max_duration:
                score *= 0.8
                evaluation_reasons.append("片段过长")

            # 内容类型评分
            if content_rules.get("prefer_speech", True) and unit.get("type") == "speech":
                score *= 1.5
                evaluation_reasons.append("语音内容加分")

            # 情感评分
            if content_rules.get("prefer_high_sentiment", False):
                sentiment = unit.get("sentiment", "neutral")
                if sentiment in ["positive", "joy", "love", "enthusiasm"]:
                    score *= 1.3
                    evaluation_reasons.append("积极情感加分")

            # 文本质量评分
            text = unit.get("text", "")
            if text:
                # 检查是否为完整句子
                if content_rules.get("require_complete_sentences", False):
                    if text.strip().endswith(('.', '!', '?', '。', '！', '？')):
                        score *= 1.2
                        evaluation_reasons.append("完整句子加分")

                # 检查文本长度
                if len(text.strip()) > 10:
                    score *= 1.1
                    evaluation_reasons.append("文本内容丰富加分")

            evaluated_unit = unit.copy()
            evaluated_unit["evaluation_score"] = score
            evaluated_unit["evaluation_reasons"] = evaluation_reasons
            evaluated_units.append(evaluated_unit)

        # 按评分排序
        evaluated_units.sort(key=lambda x: x["evaluation_score"], reverse=True)

        return evaluated_units

    async def _select_segments(
        self,
        evaluated_units: List[Dict[str, Any]],
        template: Dict[str, Any],
        video_duration: float
    ) -> List[Dict[str, Any]]:
        """选择剪辑片段"""
        selected_segments = []
        target_duration = template["target_duration"]
        max_segments = template["max_segments"]
        content_rules = template["content_rules"]

        current_duration = 0
        segments_count = 0

        for unit in evaluated_units:
            unit_duration = unit.get("duration", 0)

            # 检查是否达到最大片段数
            if segments_count >= max_segments:
                break

            # 检查是否会超过目标时长
            if current_duration + unit_duration > target_duration * 1.2:  # 允许20%的误差
                # 如果还有空间，尝试截断片段
                if current_duration < target_duration * 0.8:
                    remaining_time = target_duration - current_duration
                    if remaining_time > content_rules.get("min_segment_duration", 2):
                        truncated_unit = unit.copy()
                        truncated_unit["end_time"] = truncated_unit["start_time"] + remaining_time
                        truncated_unit["duration"] = remaining_time
                        truncated_unit["text"] = truncated_unit["text"][:int(len(truncated_unit["text"]) * remaining_time / unit_duration)]
                        selected_segments.append(truncated_unit)
                        current_duration += remaining_time
                        segments_count += 1
                break

            # 添加片段
            selected_segments.append(unit)
            current_duration += unit_duration
            segments_count += 1

        return selected_segments

    async def _optimize_segments(
        self,
        segments: List[Dict[str, Any]],
        template: Dict[str, Any],
        original_duration: float
    ) -> List[Dict[str, Any]]:
        """优化片段顺序和时长"""
        if not segments:
            return segments

        optimized_segments = []

        # 1. 时间顺序调整
        time_sorted_segments = sorted(segments, key=lambda x: x["start_time"])

        # 2. 添加开头和结尾预留时间
        opening_duration = template.get("opening_duration", 3)
        ending_duration = template.get("ending_duration", 2)

        # 3. 调整片段时长
        target_total = template["target_duration"] - opening_duration - ending_duration
        current_total = sum(seg.get("duration", 0) for seg in time_sorted_segments)

        if current_total > target_total:
            # 需要缩短片段
            scale_factor = target_total / current_total
            for segment in time_sorted_segments:
                adjusted_segment = segment.copy()
                original_duration = adjusted_segment.get("duration", 0)
                adjusted_duration = original_duration * scale_factor

                # 确保不低于最小时长
                min_duration = template["content_rules"].get("min_segment_duration", 2)
                if adjusted_duration < min_duration:
                    adjusted_duration = min_duration

                adjusted_segment["duration"] = adjusted_duration
                adjusted_segment["end_time"] = adjusted_segment["start_time"] + adjusted_duration
                optimized_segments.append(adjusted_segment)
        else:
            optimized_segments = time_sorted_segments

        return optimized_segments

    def _estimate_output_duration(
        self,
        segments: List[Dict[str, Any]],
        template: Dict[str, Any]
    ) -> float:
        """估算输出视频时长"""
        content_duration = sum(seg.get("duration", 0) for seg in segments)
        opening_duration = template.get("opening_duration", 0)
        ending_duration = template.get("ending_duration", 0)

        # 添加转场时间
        transition_time = len(segments) * 0.5 if len(segments) > 1 else 0

        total_duration = content_duration + opening_duration + ending_duration + transition_time
        return total_duration